package org.changs.control.ui.offlinemap;

import android.content.Context;
import android.support.v7.app.AlertDialog;

import com.amap.api.maps.offlinemap.OfflineMapCity;
import com.amap.api.maps.offlinemap.OfflineMapManager;
import com.amap.api.maps.offlinemap.OfflineMapProvince;
import com.amap.api.maps.offlinemap.OfflineMapStatus;
import com.google.gson.JsonObject;

import org.changs.aplug.base.BasePresenter;
import org.changs.aplug.exception.AppException;
import org.changs.aplug.utils.EmptyUtils;
import org.changs.aplug.utils.FileUtils;
import org.changs.aplug.utils.JsonUtils;
import org.changs.aplug.utils.NetworkUtils;
import org.changs.aplug.utils.WifiUtils;
import org.changs.control.event.NetConnectEvent;
import org.changs.control.event.RemoteIpEvent;
import org.changs.control.event.RequestMsgEvent;
import org.changs.servlet.AplugClient;
import org.changs.servlet.CommunicationConfig;
import org.changs.servlet.IOUtils;
import org.changs.servlet.message.VMapMessage;
import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode;

import java.io.File;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import javax.inject.Inject;
import javax.inject.Singleton;

import aplug.AppConfig;
import aplug.data.prefs.PreferencesHelper;
import io.reactivex.Observable;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.schedulers.Schedulers;
import timber.log.Timber;

import static org.changs.control.ui.offlinemap.OfflineMapContract.STATE_CAN_SYNC;
import static org.changs.control.ui.offlinemap.OfflineMapContract.STATE_SYNCING;
import static org.changs.control.ui.offlinemap.OfflineMapContract.STATE_SYNC_DONE;

/**
 * Created by yincs on 2017/10/9.
 */

@Singleton
public class OfflineMapPresenter extends BasePresenter<OfflineMapContract.V> implements OfflineMapContract.P {


    private final Context mContext;
    private final OfflineMapManager mOfflineMapManager;
    private List<Object> mOfflineMapProvinceList;
    private int mSyncState;
    private String mRemoteIp;
    private final PreferencesHelper mPreferencesHelper;
    private boolean mHasInit;

    @Inject
    public OfflineMapPresenter(Context context, PreferencesHelper preferencesHelper) {
        this.mPreferencesHelper = preferencesHelper;
        this.mContext = context;
        this.mOfflineMapManager = new OfflineMapManager(context, new OfflineMapManager.OfflineMapDownloadListener() {
            @Override
            public void onDownload(int status, int completeCode, String name) {
                if (status == OfflineMapStatus.SUCCESS) {
                    setSyncMapState(STATE_CAN_SYNC);
                    checkProvinceState();
                    syncVehicleMap();
                }
                if (isAttachView()) {
                    getMvpView().notifyDownload();
                }
            }

            @Override
            public void onCheckUpdate(boolean hasNew, String name) {
                if (isAttachView()) getMvpView().notifyDownload();
            }

            @Override
            public void onRemove(boolean success, String name, String describe) {
                Timber.d("onRemove() called with: success = [" + success + "], name = [" + name + "], describe = [" + describe + "]");
                if (success) checkProvinceState();
                if (isAttachView()) getMvpView().notifyDownload();
            }
        });

        this.mOfflineMapManager.setOnOfflineLoadedListener(() -> {
            mHasInit = true;
            mOfflineMapProvinceList = getOfflineMapProvinceList();
            checkProvinceState();
            try {
                //初始化成功后自动下载全国概要图
                mOfflineMapManager.downloadByCityCode("000");
            } catch (Exception ignored) {
            }
            if (isAttachView()) {
                getMvpView().hideLoading();
                getMvpView().showCity(mOfflineMapProvinceList);
            }
            if (mPreferencesHelper.isWifiAutoUpdate() && WifiUtils.isWifiConnected(mContext)) {
                update();
            }
        });
        this.mSyncState = mPreferencesHelper.isAlreadySyncMap() ? STATE_SYNC_DONE : STATE_CAN_SYNC;
        EventBus.getDefault().register(this);
    }

    @Subscribe(threadMode = ThreadMode.MAIN)
    public void onEvent(RemoteIpEvent event) {
        Timber.d("onEvent(RemoteIpEvent) called with: " + "event.remoteIP = [" + event.remoteIP + "]");
        mRemoteIp = event.remoteIP;
        if (EmptyUtils.isEmpty(mRemoteIp)) {
            if (mSyncState == STATE_SYNCING)
                setSyncMapState(STATE_CAN_SYNC);
        } else {
            syncVehicleMap();
        }
    }

    @Subscribe(threadMode = ThreadMode.MAIN)
    public void onEvent(RequestMsgEvent event) {
        if (event.action.equals(IOUtils.Event.SYNC_MAP_DONE)) {
            setSyncMapState(STATE_SYNC_DONE);
        }
    }

    @Subscribe(threadMode = ThreadMode.MAIN)
    public void onEvent(NetConnectEvent event) {
        if (mPreferencesHelper.isWifiAutoUpdate() && mHasInit) {
            update();
        }
    }

    private void setSyncMapState(@OfflineMapContract.State int state) {
        mSyncState = state;
        if (state == STATE_CAN_SYNC) {
            mPreferencesHelper.setAlreadySyncMap(false);
        } else if (state == STATE_SYNC_DONE) {
            mPreferencesHelper.setAlreadySyncMap(true);
        }
        if (isAttachView()) getMvpView().notifySyncMapStateChange(mSyncState);
    }

    /**
     * 同步车载的地图
     */
    @Override
    public void syncVehicleMap() {
        if (mSyncState != STATE_CAN_SYNC) {
            Timber.d("syncVehicleMap() 当前不需要同步 ");
            return;
        }
        if (EmptyUtils.isEmpty(mRemoteIp)) {
            return;
        }
        Timber.d("mRemoteIp = " + mRemoteIp);
        setSyncMapState(STATE_SYNCING);
        Observable
                .fromCallable(() -> {
                    final File vmap2Directory = new File(AppConfig.getMapRootFile(), "data/VMAP2");
                    final File[] files = vmap2Directory.listFiles(pathname -> pathname.getName().endsWith(".zip.tmp.dt"));

                    List<VMapMessage> result = new ArrayList<>();
                    for (File file : files) {
                        final String json = FileUtils.readFile2String(file, null);
                        final VMapMessage vMapMessage = JsonUtils.parseObject(json, VMapMessage.class);
                        result.add(vMapMessage);
                    }
                    if (result.size() == 0) throw new AppException("当前没有地图可更新");
                    final String data = JsonUtils.stringify(result);
                    System.out.println("data = " + data);

                    JsonObject request = new JsonObject();
                    request.addProperty(IOUtils.EXTRA_ACTION, IOUtils.Action.SYM_MAP_DATA);
                    request.addProperty(IOUtils.EXTRA_DATA, data);
                    try {
                        AplugClient.send(mRemoteIp, CommunicationConfig.S3_SERVER_PORT, request.toString());
                    } catch (Exception e) {
                        setSyncMapState(STATE_CAN_SYNC);
                        return false;
                    }
                    return true;
                })
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(aBoolean -> {
                    if (!aBoolean) setSyncMapState(STATE_CAN_SYNC);
                }, throwable -> setSyncMapState(STATE_CAN_SYNC));
    }


    @Override
    public void attachView(OfflineMapContract.V v) {
        super.attachView(v);
        if (mOfflineMapProvinceList != null) {
            getMvpView().hideLoading();
            getMvpView().showCity(mOfflineMapProvinceList);
        } else {
            getMvpView().showLoading().setMessage("正在加载离线地图...");
        }
        getMvpView().notifySyncMapStateChange(mSyncState);
    }

    @Override
    public void enableWifiAutoUpdate(boolean enable) {
        mPreferencesHelper.setWifiAutoUpdate(enable);
        if (enable) update();
    }

    @Override
    public void download(OfflineMapProvince province) {
        if (province.getCityList().size() == 1) {
            download(province.getCityList().get(0));
            return;
        }
        if (!NetworkUtils.isConnected(mContext)) {
            if (isAttachView()) getMvpView().onError("当前网络不可用");
            return;
        }
        for (OfflineMapCity city : province.getCityList()) {
            if (city.getState() == OfflineMapStatus.WAITING
                    || city.getState() == OfflineMapStatus.LOADING) continue;
            try {
                mOfflineMapManager.downloadByCityCode(city.getCode());
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        province.setState(OfflineMapStatus.LOADING);
    }

    @Override
    public void download(OfflineMapCity city) {
        if (!NetworkUtils.isConnected(mContext)) {
            if (isAttachView()) getMvpView().onError("当前网络不可用");
            return;
        }
        try {
            mOfflineMapManager.downloadByCityCode(city.getCode());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public void delete(OfflineMapProvince province) {
        new AlertDialog.Builder(getMvpView().getContext())
                .setMessage("确定删除" + province.getProvinceName() + "吗")
                .setPositiveButton("删除", (dialog, which) -> {
                    for (OfflineMapCity offlineMapCity : province.getCityList()) {
                        mOfflineMapManager.remove(offlineMapCity.getCity());
                    }
                })
                .setNegativeButton("取消", (dialog, which) -> dialog.dismiss())
                .create()
                .show();
    }

    @Override
    public void delete(OfflineMapCity city) {
        new AlertDialog.Builder(getMvpView().getContext())
                .setMessage("确定删除" + city.getCity() + "吗")
                .setPositiveButton("删除", (dialog, which) -> mOfflineMapManager.remove(city.getCity()))
                .setNegativeButton("取消", (dialog, which) -> dialog.dismiss())
                .create()
                .show();
    }

    @Override
    public void pause() {
        mOfflineMapManager.pause();
    }

    @Override
    public void update() {
        for (OfflineMapCity city : mOfflineMapManager.getDownloadOfflineMapCityList()) {
            if (city.getState() == OfflineMapStatus.NEW_VERSION) {
                try {
                    mOfflineMapManager.downloadByCityCode(city.getCode());
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }

    private List<Object> getOfflineMapProvinceList() {
        List<Object> result = new ArrayList<>();
        result.add("热门城市");
        result.add(getCity2Province("010"));//北京市
        result.add(getCity2Province("021"));//上海市
        result.add(getCity2Province("020"));//广州市
        result.add(getCity2Province("0755"));//深圳市
        result.add(getCity2Province("022"));//天津市
        result.add(getCity2Province("023"));//重庆市
        result.add("全部");
        OfflineMapProvince especialCity = new OfflineMapProvince();
        especialCity.setCityList(new ArrayList<>());
        especialCity.setProvinceName("特别行政区");
        ArrayList<OfflineMapProvince> offlineMapProvinceList = mOfflineMapManager.getOfflineMapProvinceList();
        Timber.d("offlineMapProvinceList.size() = " + offlineMapProvinceList.size());
        Iterator<OfflineMapProvince> iterator = offlineMapProvinceList.iterator();
        while (iterator.hasNext()) {
            OfflineMapProvince next = iterator.next();
            if (next.getCityList().size() == 1) {
                OfflineMapCity city = next.getCityList().get(0);
                Timber.d("city.getCity() = " + city.getCity());
                Timber.d("city.getCode() = " + city.getCode());
                String name = next.getProvinceName();
                if (name.contains("香港") || name.contains("澳门")) {
                    especialCity.getCityList().add(city);
                }
                iterator.remove();
            }
        }
        Timber.d("offlineMapProvinceList.size() = " + offlineMapProvinceList.size());
        result.addAll(offlineMapProvinceList);
        result.add(especialCity);
        return result;
    }

    private OfflineMapProvince getCity2Province(String cityCode) {
        return getCity2Province(mOfflineMapManager.getItemByCityCode(cityCode));
    }

    private OfflineMapProvince getCity2Province(OfflineMapCity city) {
        OfflineMapProvince province = new OfflineMapProvince();
        province.setCityList(new ArrayList<>());
        province.getCityList().add(city);
        province.setProvinceName(city.getCity());
        return province;
    }

    private void checkProvinceState() {
        for (Object obj : mOfflineMapProvinceList) {
            if (!(obj instanceof OfflineMapProvince)) continue;
            OfflineMapProvince province = (OfflineMapProvince) obj;
            ArrayList<OfflineMapCity> cityList = province.getCityList();
            if (cityList.size() == 1) continue;
            int successCount = 0;
            for (OfflineMapCity city : cityList) {
                if (city.getState() == OfflineMapStatus.SUCCESS) {
                    successCount++;
                }
            }
            if (successCount == cityList.size()) {
                province.setState(OfflineMapStatus.SUCCESS);
            } else {
                province.setCompleteCode(successCount * 100 / province.getCityList().size());
            }
        }
    }
}
